home *** CD-ROM | disk | FTP | other *** search
- {═════════════════════════════ DOS21_0A.PAS ══════════════════════════════}
- { ───────── Turbo 4.0/5.0 stay-resident demonstration program ───────── }
- { Copyright (c) 1989 Richard W. Prescott }
- { This Unit contains the assembly code for the basic interrupt routine, }
- { which is installed automatically by the Unit Initialization code. The }
- { original interrupt vector is stored in the current Code segment, which }
- { simplifies chaining to the original interrupt routine. This routine }
- { traps only function $0A (Buffered Input), chaining to the original }
- { interrupt $21 vector for all other function requests. The assembly }
- { code issues a FAR Call via the Pointer variable PascalCode, which must }
- { be initialized to point to an appropriate interrupt service routine. }
- {═════════════════════════════════════════════════════════════════════════}
- { This Unit was compiled and assembled using Turbo Pascal Version 5.0 }
- { and TP&Asm Version 2 ß. TP&Asm provides an integrated compile-time }
- { assembler within the Turbo development environment (and the command }
- { line compiler TPC), resulting in an ASSEMBLY Development Environment }
- { which is identical to your PASCAL Development Environment. }
- { }
- { TP&Asm Version 2.0 will be available from me for $49 plus $3 P&H. The }
- { current Beta Test Version 2 ß is available now for $39 plus $3 P&H, }
- { with a free upgrade to 2.0 when it becomes available. }
- { Please see the README file for further information. }
- {═════════════════════════════════════════════════════════════════════════}
-
- Unit DOS21_0A;
-
- INTERFACE
-
- PROCEDURE IRestore;
- PROCEDURE IReturn;
- PROCEDURE IChain;
-
- TYPE
- UserRegs = RECORD
- CASE INTEGER OF
- 0: (Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp,Ip,Cs,Flags: WORD);
- 1: (Al,Ah,Bl,Bh,Cl,Ch,Dl,Dh : BYTE);
- END; {UserRegs}
- VAR
- PascalCode: Pointer;
- UserSP,UserSS: WORD;
- User: ^UserRegs absolute UserSP;
- CONST
- CommandSig: WORD = 0;
-
- {═══════════════════════════════ SetSpLow ════════════════════════════════}
- { Simple inline directive used in Shell to insure that "resident" stack }
- { doesn't overlay the Exec Return. }
- {═══════════════════════════════ SetSpLow ════════════════════════════════}
- PROCEDURE SetSpLow; Asm Mov Sp,$180; {- Inline Directive -}
-
-
- {═════════════════════════════ DefaultDrive ══════════════════════════════}
- { Returns the default drive as a capital letter. }
- {═════════════════════════════ DefaultDrive ══════════════════════════════}
- FUNCTION DefaultDrive: CHAR; {- Inline Directive -}
- ASSEMBLE
- Mov Ah,$19
- Int $21
- Add Al,$41
- END; {Assemble}
-
- {═════════════════════════ FreeEnvironmentBlock ══════════════════════════}
- { Reduces resident memory usage by freeing the environment block for use }
- { by the next process. }
- {═════════════════════════ FreeEnvironmentBlock ══════════════════════════}
- PROCEDURE FreeEnvironmentBlock; {- Inline Directive -}
- ASSEMBLE
- Push PrefixSeg
- Pop Es
- Mov Bx,$2C ;Addr of Environment Seg
- Mov Es,Es:[Bx] ;Seg to release
- Mov Ah,$49
- Int $21
- END; {Assemble}
-
-
- IMPLEMENTATION
-
- CONST
- ActiveFlag: BOOLEAN = FALSE;
-
-
- {════════════════════════════════ CsData ═════════════════════════════════}
- { The CSDATA construct is used to store data in the current Code Segment. }
- { The original interrupt address Dos21Vec MUST be stored in this Code }
- { Segment to allow Chaining to the original interrupt routine with all of }
- { the User Registers intact. (The remaining variables COULD be stored in }
- { the Data Segment and referenced after "Mov Ax,SEG Data" & "Mov Ds,Ax"). }
- { CsData Variables are available throughout the current Unit. }
- {════════════════════════════════ CsData ═════════════════════════════════}
- CsData
- Dos21Vec Dd 0
- OurDs Dw 0
- OurSs Dw 0
- OurSp Dw 0
- OurBp Dw 0
- END; {CsData}
-
- {═════════════════════════════════ IHook ═════════════════════════════════}
- { This is the assembly portion of the interrupt service routine. }
- { For function requests other than $0A, chain to the original interrupt }
- { using an indirect jump to the address Dos21Vec stored in this Code }
- { Segment. For $0A, save registers, then restore Ds (stored in this Code }
- { Segment) and check ActiveFlag to avoid re-entrancy. If not active, }
- { save user stack frame and restore the Turbo program stack frame. }
- { Finally, issue an indirect call to the address stored in the Pointer }
- { PascalCode. An ordinary return from PascalCode results in an automatic }
- { chain to the original interrupt. (But see also IReturn and IChain). }
- { ── The Pascal code for the Interrupt Service must be a FAR Procedure ── }
- {═════════════════════════════════ IHook ═════════════════════════════════}
- PROCEDURE IHook; Forward;
- Internal Hook;
- ;- Use INTERNAL to eliminate standard Pascal Startup Code
-
- CODE SEGMENT
-
- IHook Proc Near
- Cmp Ah,0A
- IF NE Jmp Dos21Vec ;- (TP&Asm generates an automatic Cs override)
- Push Bp,Es,Di,Ds,Si,Dx,Cx,Bx,Ax
-
- Mov Ax,Ds ; Store user signature in Ax
-
- Mov Ds,OurDs ; Restore Our Ds
-
- Cmp CommandSig,0 ; First Call is from COMMAND.COM ... Store Signature
- IF Z Mov CommandSig,Ax
- Cmp ActiveFlag,0 ;NOW check Flag stored in our DS
- jNZ Chain
- Inc ActiveFlag ; =1 until Resume
-
- Mov UserSS,Ss ; Save User Stack Ss:Sp in Our Ds
- Mov UserSP,Sp ; (other registers stored on User Stack)
- Mov Ss,OurSs ; Switch to Our Stack Frame
- Mov Sp,OurSp
- Mov Bp,OurBp
-
- Call PascalCode ; pointer to Pascal Service Routine
-
- Mov Ss,UserSS ; Restore User Stack Ss:Sp From Our Ds
- Mov Sp,UserSP
- Mov ActiveFlag,0 ; Reset Flag stored in our DS
- Chain:
- Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;Restore user registers
- Jmp Dos21Vec
- IHook ENDP
- CODE ENDS
- END; {INTERNAL Hook}
-
-
- {═════════════════════════════════ IInit ═════════════════════════════════}
- { Store Turbo program registers Ds, Ss, Sp, and Bp, and the current value }
- { of the interrupt $21 vector, in the current Code Segment. Set the new }
- { value of the interrupt $21 vector to point to INTERNAL Procedure IHook. }
- {═════════════════════════════════ IInit ═════════════════════════════════}
- PROCEDURE IInit;
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- ASSEMBLE
-
- Mov OurDs,Ds
- Mov OurSs,Ss
- Mov OurSp,Sp
- Mov OurBp,Bp
-
- Mov Ax,03521 ; Get Interrupt into Es:Bx
- Int 021 ;-Store in Code Seg to allow Chaining
- Mov W Dos21Vec,Bx ; This Assembly Reference will link in CsData
- Mov W Dos21Vec+2,Es
-
- Mov Ax,02521 ; Set Interrupt to Ds:Dx
- Push Cs
- Pop Ds
- Mov Dx,Offset IHook ; This Assembly Reference will link in IHook
- Int 021
- Mov Ds,OurDs
-
- END; {Assemble}
- END; {PROCEDURE IInit}
-
-
- {═══════════════════════════════ IRestore ════════════════════════════════}
- { Restore the interrupt $21 vector to the value saved during IInit. See }
- { the Procedure Shell in CMDQ.PAS. }
- {═══════════════════════════════ IRestore ════════════════════════════════}
- PROCEDURE IRestore;
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- ASSEMBLE
- Mov Ax,02521 ; Set Interrupt to Ds:Dx
- Push Ds
- Lds Dx,Dos21Vec
- Int 021
- Pop Ds
- END; {Assemble}
- END; {IRestore;}
-
-
- {════════════════════════════════ IReturn ════════════════════════════════}
- { Set Inactive Flag, restore user registers, and return from interrupt. }
- { May be called from within nested procedures. User registers may be }
- { inspected/modified before return via the User^ record (User^.Bx, etc). }
- {════════════════════════════════ IReturn ════════════════════════════════}
- PROCEDURE IReturn;
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- ASSEMBLE
- Mov Ss,UserSS ;Restore User Stack Ss:Sp From Our Ds
- Mov Sp,UserSP
- Mov ActiveFlag,0 ;Reset Flag stored in our DS
- Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;Restore user registers
- Iret
- END; {Assemble}
- END; {IReturn;}
-
-
- {════════════════════════════════ IChain ═════════════════════════════════}
- { Set Inactive Flag, restore user registers, and jump to old interrupt. }
- { May be called from within nested procedures. User registers may be }
- { inspected/modified before chain via the User^ record (User^.Bx, etc). }
- {════════════════════════════════ IChain ═════════════════════════════════}
- PROCEDURE IChain;
- {$S-} BEGIN {$S+} {- Don't generate Stack check code -}
- ASSEMBLE
- Mov Ss,UserSS ;Restore User Stack Ss:Sp From Our Ds
- Mov Sp,UserSP
- Mov ActiveFlag,0 ;Reset Flag stored in our DS
- Pop Ax,Bx,Cx,Dx,Si,Ds,Di,Es,Bp ;Restore user registers
- Jmp Dos21Vec
- END; {Assemble}
- END; {IChain;}
-
-
- {═════════════════════════════ Initialiation ═════════════════════════════}
- { Automatically install interrupt system. }
- {═════════════════════════════ Initialiation ═════════════════════════════}
- BEGIN
- IInit;
- END.
-
-